package com.stack.common.utils;

import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;

public class ImageUtils {

    private static Logger logger = LoggerFactory.getLogger(ImageUtils.class);

    /**
     * 根据指定大小压缩图片
     *
     * @param imageBytes  源图片字节数组
     * @param desFileSize 指定图片大小，单位kb
     * @return 压缩质量后的图片字节数组
     */
    public static byte[] compressPicForScale(byte[] imageBytes, long desFileSize) {
        if (imageBytes == null || imageBytes.length <= 0 || imageBytes.length < desFileSize * 1024) {
            return imageBytes;
        }
        long srcSize = imageBytes.length;
        double accuracy = getAccuracy(srcSize / 1024);
        try {
            while (imageBytes.length > desFileSize * 1024) {
                ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes);
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream(imageBytes.length);
                Thumbnails.of(inputStream)
                        .scale(accuracy)
                        .outputQuality(accuracy)
                        .toOutputStream(outputStream);
                imageBytes = outputStream.toByteArray();
            }
            logger.info("【图片压缩】| 图片原大小={}kb | 压缩后大小={}kb", srcSize / 1024, imageBytes.length / 1024);
        } catch (Exception e) {
            logger.error("【图片压缩】msg=图片压缩失败!", e);
        }
        return imageBytes;
    }

    /**
     * 自动调节精度(经验数值)
     *
     * @param size 源图片大小
     * @return 图片压缩质量比
     */
    private static double getAccuracy(long size) {
        double accuracy;
        if (size < 900) {
            accuracy = 0.85;
        } else if (size < 2047) {
            accuracy = 0.6;
        } else if (size < 3275) {
            accuracy = 0.44;
        } else {
            accuracy = 0.4;
        }
        return accuracy;
    }

    public static String resizeImageTo30K(String base64Img) {
        try {
            System.out.println("--------- 图片压缩处理 ----------");
            BufferedImage src = base64String2BufferedImage(base64Img);
            BufferedImage output = Thumbnails.of(src).size(240, 320).asBufferedImage();
            String base64 = imageToBase64(output);
            while (base64.length() - base64.length() / 8 * 2 > 30000) {
                output = Thumbnails.of(output).scale(0.9f).asBufferedImage();
                base64 = imageToBase64(output);
            }
            return base64;
        } catch (Exception e) {
            return base64Img;
        }
    }

    public static String resizeImageToCustomK(String base64Img, int customK) {
        try {
            System.out.println("--------- 图片压缩处理 ----------");
            BufferedImage src = base64String2BufferedImage(base64Img);
            BufferedImage output = Thumbnails.of(src).size(240, 320).asBufferedImage();
            String base64 = imageToBase64(output);
            while (base64.length() - base64.length() / 8 * 2 > (customK*1000)) {
                output = Thumbnails.of(output).scale(0.9f).asBufferedImage();
                base64 = imageToBase64(output);
            }
            return base64;
        } catch (Exception e) {
            return base64Img;
        }
    }

    private static BufferedImage base64String2BufferedImage(String base64string) throws IOException {
        BufferedImage image = null;
        InputStream stream = null;
        try {
            stream = BaseToInputStream(base64string);
            image = ImageIO.read(stream);
        } catch (IOException e) {

        } finally {
            stream.close();
        }
        return image;
    }

    private static String imageToBase64(BufferedImage bufferedImage) throws IOException {
        Base64 encoder = new Base64();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            ImageIO.write(bufferedImage, "jpg", baos);
        } catch (IOException e) {

        } finally {
            baos.close();
        }
        return new String(encoder.encode((baos.toByteArray())));
    }

    /**
     * base64转inputStream
     * @param base64string
     * @return
     */
    private static InputStream BaseToInputStream(String base64string){
        ByteArrayInputStream stream = null;
        try {
            BASE64Decoder decoder = new BASE64Decoder();
            byte[] bytes1 = decoder.decodeBuffer(base64string);
            stream = new ByteArrayInputStream(bytes1);
        } catch (Exception e) {
            // TODO: handle exception
        }
        return stream;
    }

    /**
     * 判断base64图片大小
     * @param base64Pic
     * @param size
     * @return
     */
    public static boolean isBase64ImageSizeLegal(String base64Pic, int size) {
        int picSize = (base64Pic.length() - (base64Pic.length() / 8) * 2) / 1024;  //单位kb
        return picSize <= size;
    }

    /**
     * 指定图片宽度和高度或压缩比例对图片进行压缩
     *
     * @param imgsrc 源图片地址
     * @param imgdist 目标图片地址
     * @param widthdist 压缩后图片的宽度
     * @param heightdist 压缩后图片的高度
     */
    public static void reduceImg(String imgsrc, String imgdist, int widthdist, int heightdist) throws IOException {
        //创建文件输出流
        FileOutputStream out = null;
        try {
            File srcfile = new File(imgsrc);
            // 检查图片文件是否存在
            if (!srcfile.exists()) {
                System.out.println("文件不存在");
            }
            //获得源图片的宽高存入数组中
            int[] results = getImgWidthHeight(srcfile);
            if (results == null || results[0] == 0 || results[1] == 0) {
                return;
            }
//            else {
//                Float rate;
//                if(results[0] > widthdist) {    //800
//                    rate = Float.intBitsToFloat(widthdist) / Float.intBitsToFloat(results[0]);
//                    results[0] = widthdist;
//                    results[1] = (int) (results[1] * rate);
//                }
//                if(results[1] > heightdist) {   //1280
//                    rate = Float.intBitsToFloat(heightdist) / Float.intBitsToFloat(results[1]);
//                    results[1] = heightdist;
//                    results[0] = (int) (results[0] * rate);
//                }
//                //按比例缩放或扩大图片大小，将浮点型转为整型
//                widthdist = results[0];
//                heightdist = results[1];
//            }
            // 开始读取文件并进行压缩
            Image src = ImageIO.read(srcfile);

            // 构造一个类型为预定义图像类型之一的 BufferedImage
            BufferedImage tag = new BufferedImage((int) widthdist, (int) heightdist, BufferedImage.TYPE_INT_RGB);

            //绘制图像  getScaledInstance表示创建此图像的缩放版本，返回一个新的缩放版本Image,按指定的width,height呈现图像
            //Image.SCALE_SMOOTH,选择图像平滑度比缩放速度具有更高优先级的图像缩放算法。
            tag.getGraphics().drawImage(src.getScaledInstance(widthdist, heightdist, Image.SCALE_SMOOTH), 0, 0, null);

            //创建文件输出流
            out = new FileOutputStream(imgdist);
            //将图片按JPEG压缩，保存到out中
//            JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
//            encoder.encode(tag);
            ImageIO.write(tag, "JPEG", out);
            //关闭文件输出流
        } catch (Exception ef) {
            ef.printStackTrace();
        } finally {
            out.close();
        }
    }

    /**
     * 获取图片宽度和高度
     *
     * @param file
     * @return 返回图片的宽度
     */
    public static int[] getImgWidthHeight(File file) throws IOException {
        InputStream is = null;
        BufferedImage src = null;
        int result[] = { 0, 0 };
        try {
            // 获得文件输入流
            is = new FileInputStream(file);
            // 从流里将图片写入缓冲图片区
            src = ImageIO.read(is);
            result[0] = src.getWidth(null); // 得到源图片宽
            result[1] = src.getHeight(null);// 得到源图片高
            is.close();  //关闭输入流
        } catch (Exception ef) {
            ef.printStackTrace();
        } finally {
            is.close();
        }

        return result;
    }

    public static String resizeImageToBase64WithHead(String imageUrl, long desFileSize) {
        byte[] imageBytes = Base64ImgUtil.getImageByteFromUrl(imageUrl);
        BASE64Encoder encoder = new BASE64Encoder();
        if (imageBytes == null || imageBytes.length <= 0 || imageBytes.length < desFileSize * 1024) {
            return "data:image/jpeg;base64," + encoder.encode(imageBytes);
        }
        long srcSize = imageBytes.length;
        double accuracy = getAccuracy(srcSize / 1024);
        try {
            while (imageBytes.length > desFileSize * 1024) {
                ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes);
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream(imageBytes.length);
                Thumbnails.of(inputStream)
                        .scale(accuracy)
                        .outputQuality(accuracy)
                        .toOutputStream(outputStream);
                imageBytes = outputStream.toByteArray();
                inputStream.close();
                outputStream.close();
            }
            logger.info("【图片压缩】| 图片原大小={" + srcSize / 1024 + "}kb | 压缩后大小={" + imageBytes.length / 1024 + "}kb | ");
        } catch (Exception e) {
            logger.error("【图片压缩】msg=图片压缩失败!" + e);
        }
        return "data:image/jpeg;base64," + encoder.encode(imageBytes);
    }

    public static void main(String[] args) {
//        byte[] base64Image = Base64ImgUtil.getImageStrFromPathToSourceByte("C:\\Users\\24514\\Desktop\\墨计考勤人员信息\\墨计考勤人员信息\\1.jpg");
//        byte[] result = ImageUtils.compressPicForScale(base64Image, 800L);
//        BASE64Encoder encoder = new BASE64Encoder();
//        Base64ImgUtil.generateImage(encoder.encode(result), "C:\\Users\\24514\\Desktop\\墨计考勤人员信息\\墨计考勤人员信息2\\1.jpg");
        System.out.println(resizeImageToBase64WithHead("http://cdn.emodor.com/3/000000/cutout/2023040101516384923.jpg", 100));
    }

}
